package com.sky.service.user.impl;

import cn.hutool.core.date.DateException;
import com.alibaba.fastjson.JSON;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.mapper.user.OrdersMapper;
import com.sky.mapper.user.UserMapper;
import com.sky.pojo.Orders;
import com.sky.pojo.User;
import com.sky.properties.WeChatProperties;
import com.sky.service.user.WxPayService;
import com.sky.wx.wxdto.*;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CloseableHttpClient httpClient;
    @Autowired
    private WeChatProperties weChatProperties;

    @Override
    public void payment(WxPayDto wxPayDto) throws Exception {
        if (null == wxPayDto || null == wxPayDto.getOrderNumber() || "".equals(wxPayDto.getOrderNumber())) {
            throw new DateException(MessageConstant.DATA_ERROR);
        }
        Orders orders = ordersMapper.selectByNumber(wxPayDto.getOrderNumber());
        if (null == orders) {
            throw new DateException(MessageConstant.DATA_ERROR);
        }
        User user = userMapper.selectByUserId(BaseContext.getCurrentId());
        //微信下单  返回预支付订单
        myNative(orders, user);


    }

    public String wxSign(String prepayId) throws Exception {
        String message = buildMessage(weChatProperties.getAppid(),
                System.currentTimeMillis(),
                UUID.randomUUID().toString().replaceAll("-", ""),
                "prepay_id=" + prepayId);
        return sign(message.getBytes(StandardCharsets.UTF_8));
    }

    public String sign(byte[] message) throws Exception {
        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(Files.newInputStream(Paths.get(weChatProperties.getPrivateKeyFilePath())));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(merchantPrivateKey);
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    //封装签名参数
    String buildMessage(String appid, long timestamp, String nonceStr, String packageStr) {
        return appid + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packageStr + "\n";

    }

    //微信扫描支付
    private void myNative(Orders orders, User user) throws IOException {

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
        Amount amount = Amount.builder()
//                .total(orders.getAmount().intValue())
                .total(1)
                .currency("CNY")
                .build();
        NativePayDto nativePayDto = NativePayDto.builder()
                .out_trade_no(orders.getNumber())
                .notify_url(weChatProperties.getNotifyUrl())
                .mchid(weChatProperties.getMchid())
                .description("科技与狠活")
                .amount(amount)
                .appid(weChatProperties.getAppid())
                .build();

        // 请求body参数
        String reqdata = JSON.toJSONString(nativePayDto);
        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                System.out.println(EntityUtils.toString(response.getEntity()));
            } else if (statusCode == 204) {
                System.out.println(EntityUtils.toString(response.getEntity()));
            } else {
                System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }
    }

    //微信退款
    public void refunds(Orders orders,String currency) throws IOException {

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds");
        RefundAmount amount = RefundAmount.builder()
                .refund(1)
                .total(1)
                .currency(currency)
                .build();
        RefundDto refundDto = RefundDto.builder()
                .out_refund_no(UUID.randomUUID().toString().replaceAll("-", ""))
                .out_trade_no(orders.getNumber())
                .amount(amount)
                .build();
        // 请求body参数
        String reqdata = JSON.toJSONString(refundDto);
        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                System.out.println(EntityUtils.toString(response.getEntity()));
            } else if (statusCode == 204) {
                System.out.println(EntityUtils.toString(response.getEntity()));
            } else {
                System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }
    }
}
